Skip to content

Exercises

Alright, let's get some hands-on practice with useEffect!

Logging a particular value

Below, we have a signup form with several React state variables.

Our goal is to add a console.log that fires only when the value of “email” changes. We should see the user's email logged in the console whenever they edit that field.

Acceptance Criteria:

  • Whenever the user changes the value of the “email” state variable, the new value should be logged to the console.
  • Nothing should be logged when the user changes another field (for example, their city or postal code).
  • The logging should be done inside an effect, not within the onChange event handler.

Stretch Goal:

  • Update the code so that name is also logged whenever it changes.

Code Playground

import React from 'react';

function SignupForm() {
const [name, setName] = React.useState('');
const [email, setEmail] = React.useState('');
const [city, setCity] = React.useState('');
const [postalCode, setPostalCode] = React.useState(
''
);

return (
<form>
<Field
id="name"
label="Preferred Name"
value={name}
onChange={(event) => {
setName(event.target.value);
}}
/>
<Field
id="email"
type="email"
label="Email Address"
value={email}
onChange={(event) => {
setEmail(event.target.value);
}}
/>
<div className="row">
<Field
id="city"
label="City"
grow={2}
value={city}
onChange={(event) => {
setCity(event.target.value);
}}
/>
<Field
id="postal-code"
label="Postal Code"
grow={1}
value={postalCode}
onChange={(event) => {
setPostalCode(event.target.value);
}}
/>
</div>
<button>Sign up</button>
</form>
);
}

function Field({
id,
label,
type = 'text',
grow,
value,
onChange,
}) {
return (
<div
className="field"
style={{ '--grow': grow }}
>
<label htmlFor={id}>{label}</label>
preview
console

Solution:

Locally-persisted state

Let's suppose we're building an application with a “Dark Mode” toggle.

It would be really annoying if users had to keep toggling their preferred mode every time they load our application!

Let's update the code below so that the user's preference is saved in localStorage, and restored when the page loads.

In other words, the current value of isDarkMode should be "remembered", and used when the page is refreshed:

We can do this in plain JS with the following code:

// Save the value:
window.localStorage.setItem('is-dark-mode', true);
// Retrieve the value:
window.localStorage.getItem('is-dark-mode');

Acceptance Criteria:

  • The value of isDarkMode should be saved in localStorage whenever it changes, using the useEffect hook.
  • The initial value of the isDarkMode state variable should be retrieved from localStorage (or set to false if no value has been saved).
  • You can use the string "is-dark-mode" for the key.
  • Note: Items saved to localStorage are always saved as a string. You'll need to convert the stored value back to boolean. You can do this with JSON.parse().

Code Playground

/*
Local Storage cheatsheet:

// To save an item:
window.localStorage.setItem('is-dark-mode', true);

// To retrieve the value:
JSON.parse(window.localStorage.getItem('is-dark-mode'));
*/

import React from 'react';

import Toggle from './Toggle';

function App() {
const [isDarkMode, setIsDarkMode] = React.useState(false);

return (
<div
className="wrapper"
style={{
// NOTE: This is a just-for-fun mini demo, not a
// full-featured Dark Mode implementation!
'--color-bg': isDarkMode ? 'black' : 'white',
'--color-text': isDarkMode ? 'white' : 'black',
}}
>
<Toggle
label="Dark Mode"
checked={isDarkMode}
handleToggle={setIsDarkMode}
/>
</div>
);
}

export default App;

Solution:

In this video, we use a function to initialize our state variable. This pattern is discussed in the “useState Hook” lesson.

One more thing: the solution shared here won't work if using a server-side rendering framework like Next.js, Remix, or Gatsby. We'll learn more about this scenario and how to work around it later in this course.